/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.device.modular.service.impl;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vip.xiaonuo.common.enums.BizPermissionEnum;
import vip.xiaonuo.device.core.enums.Constants;
import vip.xiaonuo.device.modular.bo.*;
import vip.xiaonuo.device.modular.entity.BizCabinetDoor;
import vip.xiaonuo.device.modular.entity.BizCabinetInfo;
import vip.xiaonuo.device.modular.mapper.CabinetDoorMapper;
import vip.xiaonuo.device.modular.mapper.CabinetInfoMapper;
import vip.xiaonuo.device.modular.mapper.PermissionMapper;
import vip.xiaonuo.device.vo.CabinetInfoPerm;
import vip.xiaonuo.device.vo.CabinetInfoPermAuthUser;
import vip.xiaonuo.device.vo.Result;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备api日志Service接口实现类
 *
 * @author levin
 * @date 2022/11/30 13:27
 **/
@Service("devicePermBatchService")
public class DevicePermBatchServiceImpl extends DeviceBaseService {
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private CabinetInfoMapper cabinetInfoMapper;
    @Autowired
    private CabinetDoorMapper cabinetDoorMapper;

    @Override
    protected Integer getReqType() {
        return Constants.GETDOORAUTHLIST;
    }

    @Override
    protected Result handle(JSONObject param) {
        String cabinetCode = param.getString("cabinetcode");
        // 查找柜子&校验
        BizCabinetInfo cabinetInfo = cabinetInfoMapper.selectOne(new LambdaQueryWrapper<BizCabinetInfo>()
                .eq(BizCabinetInfo::getCabinetCode, cabinetCode)
                .eq(BizCabinetInfo::getDeleteFlag, "NOT_DELETE")
                .last("limit 1"));
        if (cabinetInfo == null) return Result.fail(String.format("柜子编码=%s,不存在", cabinetCode));

        // 获取所有的柜门
        List<BizCabinetDoor> doorList = getDoorList(cabinetInfo.getId());
        // 构建doorId -> userId -> UserPermMatrix的数据结构
        Map<String, Map<String, UserPermMatrix>> userPermDoorMap = initUserPermDoorMap(doorList);
        // 处理管理员权限
        handleAdminPerms(userPermDoorMap, cabinetInfo);

        // 只有柜子是启用状态,才需要处理用户权限
        if (cabinetInfo.getState() == 1) {
            // 处理用户权限
            handleUserAuth(userPermDoorMap, cabinetInfo.getId());
        }

        // 循环处理，生成权限列表
        List<CabinetInfoPerm> permResultList = doorList.stream().map(door -> {
            CabinetInfoPerm perm = new CabinetInfoPerm();
            perm.setCabinetcode(cabinetInfo.getCabinetCode());
            perm.setDoorcode(door.getCabinetDoorCode());
            handleAuthUsers(perm, userPermDoorMap, door);
            return perm;
        }).collect(Collectors.toList());
        return Result.ok(permResultList);
    }

    private Map<String, Map<String, UserPermMatrix>> initUserPermDoorMap(List<BizCabinetDoor> doorList) {
        Map<String, Map<String, UserPermMatrix>> map = new HashMap<>(doorList.size());
        doorList.forEach(door -> {
            Map<String, UserPermMatrix> userPermMatrixMap = new HashMap<>();
            map.put(door.getId(), userPermMatrixMap);
        });
        return map;
    }

    private List<BizCabinetDoor> getDoorList(String cabinetInfoId) {
        return cabinetDoorMapper.selectList(new LambdaQueryWrapper<BizCabinetDoor>()
                .eq(BizCabinetDoor::getCabinetInfoId, cabinetInfoId)
                .eq(BizCabinetDoor::getDeleteFlag, "NOT_DELETE"));
    }

    private void handleAdminPerms(Map<String, Map<String, UserPermMatrix>> userPermDoorMap, BizCabinetInfo cabinetInfo) {
        String cabinetInfoId = cabinetInfo.getId();
        String cabinetGroupId = cabinetInfo.getCabinetGroupId();
        // 设置柜门管理员权限
        List<CabinetDoorAdminPerm> cabinetDoorAdminPerms = permissionMapper.getCabinetDoorAdmin(cabinetInfoId);
        cabinetDoorAdminPerms.forEach(cabinetDoorAdminPerm -> {
            String doorId = cabinetDoorAdminPerm.getCabinetDoorId();
            String userId = cabinetDoorAdminPerm.getUserId();
            String userName = cabinetDoorAdminPerm.getUserName();
            String userNo = cabinetDoorAdminPerm.getUserNo();
            Map<String, UserPermMatrix> userPermMatrixMap = userPermDoorMap.get(doorId);
            setAdminAuth(userId, userName, userNo, "CABINET_DOOR", userPermMatrixMap);
        });
        // 设置柜子管理员权限，有了柜子管理员权限，说明下面的柜门都有权限
        List<CabinetInfoAdminPerm> cabinetInfoAdminPerms = permissionMapper.getCabinetInfoAdmin(cabinetInfoId);
        cabinetInfoAdminPerms.forEach(cabinetInfoAdminPerm -> {
            String userId = cabinetInfoAdminPerm.getUserId();
            String userName = cabinetInfoAdminPerm.getUserName();
            String userNo = cabinetInfoAdminPerm.getUserNo();
            userPermDoorMap.forEach((doorId, uMap) -> setAdminAuth(userId, userName, userNo, "CABINET_INFO", uMap));
        });
        // 设置组柜管理员权限，有了组柜管理员权限，说明下面的柜门都有权限
        if (StringUtils.isNotEmpty(cabinetGroupId)) {
            List<CabinetGroupAdminPerm> cabinetGroupAdminPerms = permissionMapper.getCabinetGroupAdmin(cabinetGroupId);
            cabinetGroupAdminPerms.forEach(cabinetGroupAdminPerm -> {
                String userId = cabinetGroupAdminPerm.getUserId();
                String userName = cabinetGroupAdminPerm.getUserName();
                String userNo = cabinetGroupAdminPerm.getUserNo();
                userPermDoorMap.forEach((doorId, uMap) -> setAdminAuth(userId, userName, userNo, "CABINET_GROUP", uMap));
            });
        }
    }

    private void setAdminAuth(String userId, String userName, String userNo, String deviceType, Map<String, UserPermMatrix> userPermMatrixMap) {
        UserPermMatrix userPermMatrix = userPermMatrixMap.get(userId);
        if (userPermMatrix == null) {
            userPermMatrix = UserPermMatrix.builder().userId(userId).userName(userName).userNo(userNo).isManager(true).build();
            userPermMatrixMap.put(userId, userPermMatrix);
        }
        // 设置权限
        UserPermMatrixItem userPermMatrixItem = UserPermMatrixItem.builder().permState(BizPermissionEnum.AUTHORIZED).build();
        if ("CABINET_GROUP".equals(deviceType)) {
            userPermMatrix.setCabinetGroupPerm(userPermMatrixItem);
        } else if ("CABINET_INFO".equals(deviceType)) {
            userPermMatrix.setCabinetInfoPerm(userPermMatrixItem);
        } else if ("CABINET_DOOR".equals(deviceType)) {
            userPermMatrix.setCabinetDoorPerm(userPermMatrixItem);
        }
    }

    private void handleUserAuth(Map<String, Map<String, UserPermMatrix>> userPermDoorMap, String cabinetInfoId) {
        // 获取所有用户授权列表
        List<UserPerm> permissionList = permissionMapper.getUserPerms(cabinetInfoId);
        permissionList.forEach(perm -> {
            String doorId = perm.getCabinetDoorId();
            String userId = perm.getUserId();
            String userName = perm.getUserName();
            String userNo = perm.getUserNo();
            Date startTime = perm.getPermStartTime();
            Date endTime = perm.getPermEndTime();
            Map<String, UserPermMatrix> userPermMatrixMap = userPermDoorMap.get(doorId);
            UserPermMatrix userPermMatrix = userPermMatrixMap.get(userId);
            // 如果已经是管理员了，无需再设置授权的权限了
            if (userPermMatrix != null && userPermMatrix.isManager()) return;
            if (userPermMatrix == null) {
                userPermMatrix = UserPermMatrix.builder().userId(userId).userName(userName).userNo(userNo).isManager(false).build();
            }
            // 设置三种权限
            UserPermMatrixItem userPermMatrixItem = UserPermMatrixItem.builder()
                    .permState(BizPermissionEnum.valueOf(perm.getPermState()))
                    .permStartTime(startTime)
                    .permEndTime(endTime)
                    .build();
            if ("CABINET_GROUP".equals(perm.getDeviceType())) {
                userPermMatrix.setCabinetGroupPerm(userPermMatrixItem);
            } else if ("CABINET_INFO".equals(perm.getDeviceType())) {
                userPermMatrix.setCabinetInfoPerm(userPermMatrixItem);
            } else if ("CABINET_DOOR".equals(perm.getDeviceType())) {
                userPermMatrix.setCabinetDoorPerm(userPermMatrixItem);
            }

            userPermMatrixMap.put(userId, userPermMatrix);
            userPermDoorMap.put(doorId, userPermMatrixMap);
        });
    }

    private CabinetInfoPermAuthUser buildPermAuthUser(UserPermMatrix userPermMatrix, String remark, UserPermMatrixItem userPermMatrixItem) {
        CabinetInfoPermAuthUser authUser = new CabinetInfoPermAuthUser();
        authUser.setId(userPermMatrix.getUserId());
        authUser.setCanopendoor(true);
        authUser.setCard(userPermMatrix.getUserNo());
        authUser.setIsmanager(userPermMatrix.isManager());
        authUser.setName(userPermMatrix.getUserName());

        if (!userPermMatrix.isManager()) {
            Date startTime = userPermMatrixItem.getPermStartTime();
            Date endTime = userPermMatrixItem.getPermEndTime();
            if (startTime != null && endTime != null) {
                authUser.setAuthstarttime(startTime.getTime());
                authUser.setAuthendtime(endTime.getTime());
            }
        }
        authUser.setRemark(remark);
        return authUser;
    }

    private void handleAuthUsers(CabinetInfoPerm perm, Map<String, Map<String, UserPermMatrix>> userPermDoorMap, BizCabinetDoor door) {
        List<CabinetInfoPermAuthUser> authUsers = new ArrayList<>();
        if (MapUtil.isEmpty(userPermDoorMap)) return;
        List<String> userNames = new ArrayList<>();
        userPermDoorMap.get(door.getId()).forEach((userId, permMatrix) -> {
            String userName = permMatrix.getUserName();
            String userNo = permMatrix.getUserNo();
            boolean isManager = permMatrix.isManager();
            // 没有用户ID是不加的；没有用户卡号是不加的
            if (StringUtils.isEmpty(userNo)) return;

            UserPermMatrixItem cabinetDoorMatrixItem = permMatrix.getCabinetDoorPerm();
            if (cabinetDoorMatrixItem != null) {
                // 如果柜门权限被冻结，直接返回
                if (BizPermissionEnum.FROZEN == cabinetDoorMatrixItem.getPermState()) return;
                // 有柜门权限
                if (BizPermissionEnum.AUTHORIZED == cabinetDoorMatrixItem.getPermState()) {
                    // 授权不在效期内，跳过
                    String remark = isManager ? "柜门管理员" : "用户被授予柜门权限";
                    authUsers.add(buildPermAuthUser(permMatrix, remark, permMatrix.getCabinetDoorPerm()));
                    userNames.add(userName);
                    return;
                }
            }
            // 如果没有柜门权限，但是柜门是独立权限，直接跳过
            if (door.getSeparatedPermission()) return;

            UserPermMatrixItem cabinetInfoMatrixItem = permMatrix.getCabinetInfoPerm();
            if (cabinetInfoMatrixItem != null) {
                //用户被冻结-柜子权限
                if (BizPermissionEnum.FROZEN == cabinetInfoMatrixItem.getPermState()) return;

                //用户被授权-柜子权限
                if (BizPermissionEnum.AUTHORIZED == cabinetInfoMatrixItem.getPermState()) {
                    String remark = isManager ? "柜子管理员" : "用户权限继承自柜子";
                    authUsers.add(buildPermAuthUser(permMatrix, remark, permMatrix.getCabinetInfoPerm()));
                    userNames.add(userName);
                    return;
                }
            }

            UserPermMatrixItem cabinetGroupMatrixItem = permMatrix.getCabinetGroupPerm();
            if (cabinetGroupMatrixItem != null) {
                //用户被冻结-组柜权限
                if (BizPermissionEnum.FROZEN == cabinetGroupMatrixItem.getPermState()) return;
                //用户被授权-组柜权限
                if (BizPermissionEnum.AUTHORIZED == cabinetGroupMatrixItem.getPermState()) {
                    String remark = isManager ? "组柜管理员" : "用户权限继承自组柜";
                    authUsers.add(buildPermAuthUser(permMatrix, remark, permMatrix.getCabinetGroupPerm()));
                    userNames.add(userName);
                }
            }
        });
        perm.setNames(String.join(",", userNames));
        perm.setAuthusers(authUsers);
    }
}
